//
//  KMValue.m
//  MengLiao
//
//  Created by xiuxin on 2022/7/15.
//  Copyright © 2022 ZHBen. All rights reserved.
//

#import "KMValue.h"

@interface KMValue()

@property (copy,nonatomic) id (^block)(KMValue * value, NSObject * object);

@property (strong,nonatomic) NSMutableDictionary * cache;

@property (strong,nonatomic) dispatch_semaphore_t lock;

@end

@implementation KMValue

- (instancetype)initWithBlock:(id (^)(KMValue * value, __kindof NSObject * object))block userInfo:(id)userInfo
{
    if (self = [super init])
    {
        _userInfo = userInfo;
        self.block = block;
    }
    return self;
}

- (void)setUseCache:(BOOL)useCache
{
    _useCache = useCache;
    if (_useCache && self.cache == nil)
    {
        self.cache = [NSMutableDictionary dictionary];
        self.lock = dispatch_semaphore_create(1);
    }
}

- (void)setUserInfo:(id)userInfo
{
    if (_userInfo != userInfo)
    {
        _userInfo = userInfo;
        if (_useCache)
        {
            dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
            [self.cache removeAllObjects];
            dispatch_semaphore_signal(self.lock);
        }
    }
}

+ (KMValue *)classNameValue
{
    return [[self alloc] initWithBlock:^id(KMValue *value, NSObject *object) {
        return NSStringFromClass(object.class);
    } userInfo:nil];
}

+ (KMValue *)keyPathValue:(NSString *)keyPath
{
    return [[self alloc] initWithBlock:^id(KMValue * value, NSObject * object) {
        return [object valueForKeyPath:value.userInfo];
    } userInfo:[keyPath copy]];
}

+ (KMValue *)indexValue:(NSInteger)index
{
    return [[self alloc] initWithBlock:^id(KMValue * value, NSObject * object) {
        return @([(NSArray *)object indexOfObject:value.userInfo]);
    } userInfo:@(index)];
}

+ (KMValue *)conditionValue:(id<KMValueProtocol>)value branchInfo:(NSDictionary *)branchInfo
{
    return [[self alloc] initWithBlock:^id(KMValue * val, NSObject * object) {
        NSArray * userInfo = (NSArray *)val.userInfo;
        id<KMValueProtocol> value = userInfo[0];
        NSDictionary * branchInfo = userInfo[1];
        id result = [value execute:object];
        return branchInfo[result];
    } userInfo:@[value,branchInfo]];
}

+ (KMValue *)chanValue:(NSArray<id<KMValueProtocol>> *)valueList
{
    return [[KMValue alloc] initWithBlock:^id(KMValue * value, NSObject * object) {
        for (id<KMValueProtocol> val in (NSArray *)value.userInfo)
        {
            object = [val execute:object];
            if (object == nil){
                return nil;
            }
        }
        return object;
    } userInfo:[NSArray arrayWithArray:valueList]];
}

- (id)execute:(NSObject *)object
{
    id value  = nil;
    NSString * key = nil;
    if (self.useCache)
    {
        key = [NSString stringWithFormat:@"%p",object];
        dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
        value  = self.cache[key];
        dispatch_semaphore_signal(self.lock);
        if (value != nil)
        {
            return value == [NSNull null] ? nil : value;
        }
        value = self.block(self,object);
        dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
        self.cache[key] = value ?: [NSNull null];
        dispatch_semaphore_signal(self.lock);
    }
    else
    {
        value = self.block(self,object);
    }
    return value;
}

- (void)clearCache
{
    if (self.useCache)
    {
        dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
        [self.cache removeAllObjects];
        dispatch_semaphore_signal(self.lock);
    }
    else
    {
        [self.cache removeAllObjects];
    }
}

@end
